package luanvan.bus;

import org.osmdroid.util.GeoPoint;

public class UTMLatLng {

	public GeoPoint p;
	
	public class UTM{
		public double x;
		public double y;
	}
	public double sinSquared(double x) {
		return Math.sin(x) * Math.sin(x);
	}

	public double cosSquared(double x) {
		return Math.cos(x) * Math.cos(x);
	}

	public double tanSquared(double x) {
		return Math.tan(x) * Math.tan(x);
	}

	public double sec(double x) {
		return 1.0 / Math.cos(x);
	}

	public double deg2rad(double x) {
		return x * (Math.PI / 180);
	}

	public double rad2deg(double x) {
		return x * (180 / Math.PI);
	}

	public GeoPoint UTMRefToLatLng(double easting, double northing) {
		double maj = 6378137;
		double min = 6356752.314;
		double ecc = (Math.pow(maj, 2) - Math.pow(min, 2)) / (maj * min);
		double UTM_F0 = 0.9996;
		double a = 6378137;
		double eSquared = ecc;
		double ePrimeSquared = eSquared / (1.0 - eSquared);
		double e1 = (1 - Math.sqrt(1 - eSquared))
				/ (1 + Math.sqrt(1 - eSquared));
		double x = easting - 500000.0;
		;
		double y = northing;
		double zoneNumber = 48;

		double longitudeOrigin = (zoneNumber - 1.0) * 6.0 - 180.0 + 3.0;

		// Correct y for southern hemisphere
		/*
		 * if ((ord(zoneLetter) - ord("N")) < 0) { y -= 10000000.0; }
		 */

		double m = y / UTM_F0;
		double mu = m
				/ (a * (1.0 - eSquared / 4.0 - 3.0 * eSquared * eSquared / 64.0 - 5.0 * Math
						.pow(eSquared, 3.0) / 256.0));

		double phi1Rad = mu
				+ (3.0 * e1 / 2.0 - 27.0 * Math.pow(e1, 3.0) / 32.0)
				* Math.sin(2.0 * mu)
				+ (21.0 * e1 * e1 / 16.0 - 55.0 * Math.pow(e1, 4.0) / 32.0)
				* Math.sin(4.0 * mu) + (151.0 * Math.pow(e1, 3.0) / 96.0)
				* Math.sin(6.0 * mu);

		double n = a
				/ Math.sqrt(1.0 - eSquared * Math.sin(phi1Rad)
						* Math.sin(phi1Rad));
		double t = Math.tan(phi1Rad) * Math.tan(phi1Rad);
		double c = ePrimeSquared * Math.cos(phi1Rad) * Math.cos(phi1Rad);
		double r = a
				* (1.0 - eSquared)
				/ Math.pow(
						1.0 - eSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad),
						1.5);
		double d = x / (n * UTM_F0);

		double latitude = (phi1Rad - (n * Math.tan(phi1Rad) / r)
				* (d
						* d
						/ 2.0
						- (5.0 + (3.0 * t) + (10.0 * c) - (4.0 * c * c) - (9.0 * ePrimeSquared))
						* Math.pow(d, 4.0) / 24.0 + (61.0 + (90.0 * t)
						+ (298.0 * c) + (45.0 * t * t)
						- (252.0 * ePrimeSquared) - (3.0 * c * c))
						* Math.pow(d, 6.0) / 720.0))
				* (180.0 / Math.PI);
		
		double longitude = longitudeOrigin
				+ ((d - (1.0 + 2.0 * t + c) * Math.pow(d, 3.0) / 6.0 + (5.0
						- (2.0 * c) + (28.0 * t) - (3.0 * c * c)
						+ (8.0 * ePrimeSquared) + (24.0 * t * t))
						* Math.pow(d, 5.0) / 120.0) / Math.cos(phi1Rad))
				* (180.0 / Math.PI);
		p=new GeoPoint(latitude, longitude);
		return p;
	}


	public UTM LatLngToUTMRef(double longitude, double latitude) {
		double maj = 6378137;
		double min = 6356752.314;
		double ecc = (Math.pow(maj, 2) - Math.pow(min, 2)) / (maj * min);

		double UTM_F0 = 0.9996;
		double a = maj;
		double eSquared = ecc;

		double latitudeRad = latitude * (Math.PI / 180.0);
		double longitudeRad = longitude * (Math.PI / 180.0);
		double longitudeZone = Math.floor((longitude + 180.0) / 6.0) + 1;

		// Special zone for Norway
		if (latitude >= 56.0 && latitude < 64.0 && longitude >= 3.0
				&& longitude < 12.0) {
			longitudeZone = 32;
		}

		// Special zones for Svalbard
		if (latitude >= 72.0 && latitude < 84.0) {
			if (longitude >= 0.0 && longitude < 9.0) {
				longitudeZone = 31;
			} else if (longitude >= 9.0 && longitude < 21.0) {
				longitudeZone = 33;
			} else if (longitude >= 21.0 && longitude < 33.0) {
				longitudeZone = 35;
			} else if (longitude >= 33.0 && longitude < 42.0) {
				longitudeZone = 37;
			}
		}

		double longitudeOrigin = (longitudeZone - 1) * 6 - 180 + 3;
		double longitudeOriginRad = longitudeOrigin * (Math.PI / 180.0);
		
		double ePrimeSquared = (eSquared) / (1 - eSquared);

		double n = a
				/ Math.sqrt(1 - eSquared * Math.sin(latitudeRad)
						* Math.sin(latitudeRad));
		double t = Math.tan(latitudeRad) * Math.tan(latitudeRad);
		double c = ePrimeSquared * Math.cos(latitudeRad)
				* Math.cos(latitudeRad);
		double A = Math.cos(latitudeRad) * (longitudeRad - longitudeOriginRad);

		double M = a
				* ((1 - eSquared / 4 - 3 * eSquared * eSquared / 64 - 5
						* eSquared * eSquared * eSquared / 256)
						* latitudeRad
						- (3 * eSquared / 8 + 3 * eSquared * eSquared / 32 + 45
								* eSquared * eSquared * eSquared / 1024)
						* Math.sin(2 * latitudeRad)
						+ (15 * eSquared * eSquared / 256 + 45 * eSquared
								* eSquared * eSquared / 1024)
						* Math.sin(4 * latitudeRad) - (35 * eSquared * eSquared
						* eSquared / 3072)
						* Math.sin(6 * latitudeRad));

		double X = (UTM_F0
				* n
				* (A + (1 - t + c) * Math.pow(A, 3.0) / 6 + (5 - 18 * t + t * t
						+ 72 * c - 58 * ePrimeSquared)
						* Math.pow(A, 5.0) / 120) + 500000.0);

		double Y= (UTM_F0 * (M + n
				* Math.tan(latitudeRad)
				* (A * A / 2 + (5 - t + (9 * c) + (4 * c * c))
						* Math.pow(A, 4.0) / 24 + (61 - (58 * t) + (t * t)
						+ (600 * c) - (330 * ePrimeSquared))
						* Math.pow(A, 6.0) / 720)));

		// Adjust for the southern hemisphere
		if (latitude < 0) {
			Y += 10000000.0;
		}
		UTM utm =new UTM();
		utm.x = X;
		utm.y =Y;
		return utm;

	}

}
